package com.example.demo.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.LocalDateTime;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: DELL
 * Date: 2023-05-30
 * Time: 20:02
 */
@Aspect // 添加切面注解
@Component // 随 Spring 框架启动而注入
// 创建切面 - 关于某一操作的统一类
public class UserAOP {

    // 创建切点(配置拦截规则)
    // 第一个 * -- 表示返回值为任意
    // com.example.demo.controller 为包路径
    // UserController 为类名
    // .* -- 拦截所有的方法  .a* 代表拦截所有 a 开头的方法名
    // (..) -- 表示可变参数  比如拦截 int 参数类型的方法 (int)
    //@Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    @Pointcut("execution(* com.example.demo.controller.UserController.* (..))")
    public void doPointcut() {
        // 切点只是为了配置规则, 并非具体实现. 因此为空方法
    }

    // 配置前置通知
    @Before("doPointcut()") // 里面填写针对那个切点的通知, 可以有多个切点
    public void doBefore() {
        System.out.println("执行 before 前置通知 : 登陆检验" );
    }

    @After("doPointcut()")
    public void doAfter() {
        System.out.println("执行 After 后置通知 : 登陆检验结束");
    }

    // 添加事件本身
    // ProceedingJoinPoint 表示正在执行的方法或表达式的连接点
    // 配置环绕通知
    @Around("doPointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("开始执行环绕通知" );
        long startTime = System.currentTimeMillis();

        // 因为是将方法包围起来执行, 因此只能在方法里调用本身
        Object object = joinPoint.proceed(); // 调用连接点的方法
        System.out.println("结束执行环绕通知" );
        long endTime = System.currentTimeMillis();
        System.out.println("时间差为 : " + (endTime - startTime));
        return object; // 计算时间差后并获取秒数毫秒级
    }

//    @AfterReturning("doPointcut()")
//    public void doAfterReturning() {
//        System.out.println("执行返回通知 ");
//    }

//    @AfterThrowing("doPointcut()")
//    public void doAfterThrowing() {
//        System.out.println("执行异常通知 ");
//    }
}
